package com.xinshujia.filter.authentication;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.gson.Gson;
import com.xinshujia.entity.UserEntity;
import com.xinshujia.utils.Constants;
import com.xinshujia.utils.GsonUtil;
import com.xinshujia.utils.HttpServletResponseUtil;
import com.xinshujia.utils.JwtUtil;
import com.xinshujia.utils.response.RespResult;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.lang.NonNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Date;
import java.util.Map;

/**
 * @author: 野狼上校
 * @create: 2023-05-30  22:29
 * @version: 1.0
 * @description:
 *
 * token 判断
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    private final JwtUtil jwtUtil;
    private final StringRedisTemplate redisTemplate;

    public JwtAuthenticationTokenFilter(JwtUtil jwtUtil, StringRedisTemplate redisTemplate) {
        this.jwtUtil = jwtUtil;
        this.redisTemplate = redisTemplate;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
        // 1. 从请求头中获取token
        String headerToken = request.getHeader(Constants.LOGIN_TOKEN);
        // 2. 判断token是否为空
        if (!StringUtils.isEmpty(headerToken)) {
            // 2.1. 解析Token
            DecodedJWT decodedJWT = jwtUtil.parseToken(headerToken);
            // 2.2 Token是否过期   todo Token续期
            /*分两种情况：1. 生成JwtToken的有效时间(20小时)  2.Token存入Redis中的有效时间 (20小时)*/
            if (null != decodedJWT && decodedJWT.getExpiresAt().after(new Date())) {
                // 2.3 获取Token中的内容
                Map<String, Claim> claims = decodedJWT.getClaims();
                String userid = claims.get("id").toString();
                // 2.3 判断解析Token中的username是否为空, 并且SecurityContextHolder上下文中的认证必须为空
                if (!StringUtils.isEmpty(userid)) {
                    // 3. 从redis中获取用户信息
                    String redisJson = redisTemplate.opsForValue().get(Constants.USER_INFO + userid);
                    if (!StringUtils.isEmpty(redisJson)) {
                        // 因为有日期格式，所有使用Gson解析时使用使用Adapter
                        Gson gson = GsonUtil.googleGson();
                        // 3.1 解析redis中的Token信息
                        UserEntity entity = gson.fromJson(redisJson, UserEntity.class);
                        // 3.2 Token认证
                        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(entity, null, entity.getAuthorities());
                        // 4. 将信息保存到上下文
                        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                    } else {
                        HttpServletResponseUtil httpServletResponseUtil = new HttpServletResponseUtil();
                        // redis中没有找到该token对应的数据
                        RespResult result = RespResult.Fail("token过期");
                        httpServletResponseUtil.responseAuthenticationResult(response,result);
                    }
                } else {
                    HttpServletResponseUtil httpServletResponseUtil = new HttpServletResponseUtil();
                    // token 解析失败（token非法）
                    RespResult result = RespResult.Fail("token非法");
                    httpServletResponseUtil.responseAuthenticationResult(response,result);
                }
            } else {
                HttpServletResponseUtil httpServletResponseUtil = new HttpServletResponseUtil();
                // token过期
                RespResult result = RespResult.Fail("token过期");
                httpServletResponseUtil.responseAuthenticationResult(response,result);
            }
        } else if (!containsURI(request)) {
            HttpServletResponseUtil httpServletResponseUtil = new HttpServletResponseUtil();
            RespResult result = RespResult.Fail("token不存在");
            httpServletResponseUtil.responseAuthenticationResult(response,result);
        }
        filterChain.doFilter(request, response);
    }

    /*不需要Token就能访问的URI*/
    private boolean containsURI(HttpServletRequest request) {
        //获得请求的URI
        String requestURI = request.getRequestURI();
        System.out.println("JwtAuthenticationTokenFilter: "+requestURI);
        //不需要Token就能访问的URI ---- 登录
        return requestURI.contains("login");
    }
}